package tests.labQtests;

import jeconbond.economic.EconomicEngine;
import jeconbond.economic.IEconomicEngine;
import jeconbond.economic.agent.*;
import jeconbond.economic.agent.ActIFFinRangeOfStepsAgent;
import jeconbond.economic.agent.service.IPostActServiceAgent;
import jeconbond.economic.agent.service.IPreActServiceAgent;
import jeconbond.economic.agent.service.NextStepCommandAgent;
import jeconbond.economic.natural.agent.ProvideSingleResourceAgent;
import jeconbond.economic.natural.agent.service.ObserveResourceValueAgent;
import jeconbond.economic.resources.ResourceType;
import jeconbond.economic.resources.IResourceType;
import jeconbond.economic.resources.ResourceUtils;
import jeconbond.economic.systems.IResourceRedestributionSystem;
import jeconbond.economic.systems.natural.NaturalResourceRedestributionSystem;
import jeconbond.economic.systems.natural.NaturalRRSFactory;
import jeconbond.experiment.natural.prodpossibfrontier.process.ConneryExperimentContext;
import jeconbond.experiment.natural.prodpossibfrontier.ConneryExperimentSettings;
import jeconbond.experiment.natural.prodpossibfrontier.generate.PlanWalkerStrategyBasedAgentsCreator;
import jeconbond.automata.INode;
import jeconbond.automata.Node;
import jeconbond.automata.Outcome;
import jeconbond.experiment.generate.IAgentsCreator;
import junit.framework.Assert;
import junit.framework.TestCase;

import java.lang.reflect.Field;

import laboratoryQ.experiment.process.IExperimentContext;

public class TestServiceAgents extends TestCase {
	public void testObserveResourceValueAgent() {
		IEconomicEngine engine = new EconomicEngine();
		IResourceType wood = new ResourceType("wood");
		ConneryExperimentSettings settings = new ConneryExperimentSettings();
		settings.rrsFactory = new NaturalRRSFactory();
		settings.resources = new IResourceType[] { wood, new ResourceType("r1"), new ResourceType("r2") };
		settings.stepCount = 10;

		ConneryExperimentContext context = new ConneryExperimentContext(settings);
		ObserveResourceValueAgent observer = new ObserveResourceValueAgent(
				context,
				settings.resources
		);
		Assert.assertTrue(observer instanceof IPostActServiceAgent);
		engine.addAgents(observer);
		IResourceRedestributionSystem nrrs = 
			new NaturalResourceRedestributionSystem();
		engine.processSteps(1, nrrs);
		context.getNextStepCommander().stepCounter[0]++;
		context.getRRS().storeResource(wood, 1.0);
		engine.processSteps(1, nrrs);
		context.getNextStepCommander().stepCounter[0]++;
		context.getRRS().receiveResource(wood, 0.5);
		engine.processSteps(1, nrrs);
		context.getNextStepCommander().stepCounter[0]++;
		double[] theLog = observer.getLog(wood);
		Assert.assertEquals(0.0, theLog[0]);
		Assert.assertEquals(1.0, theLog[1]);
		Assert.assertEquals(1.0 - 0.5, theLog[2]);
	}
	
	public void testNextStepCommandAgent() {
		IEconomicEngine engine = new EconomicEngine();
		int stepsize = 5;
		NextStepCommandAgent nsca = new NextStepCommandAgent(stepsize );
		Assert.assertTrue(nsca instanceof IPostActServiceAgent);
		engine.addAgents(nsca);
		Assert.assertEquals(0, nsca.stepCounter[0]);
		IResourceRedestributionSystem nrrs = 
			new NaturalResourceRedestributionSystem();
		engine.processSteps(stepsize - 1, nrrs);
		Assert.assertEquals(0, nsca.stepCounter[0]);
		engine.processSteps(1, nrrs);
		Assert.assertEquals(1, nsca.stepCounter[0]);
		engine.processSteps(stepsize * 3, nrrs);
		Assert.assertEquals(4, nsca.stepCounter[0]);
	}

	public void testEasyAut2Agent() {
		INode n1 = new Node("1");
		INode n2 = new Node("2");
		n1.getOutcomes().add(new Outcome(n2));
		n2.getOutcomes().add(new Outcome(n1));
		IAgentsCreator agentsCreator = new PlanWalkerStrategyBasedAgentsCreator();
		ConneryExperimentSettings settings = new ConneryExperimentSettings();
		settings.rrsFactory = new NaturalRRSFactory();
		settings.resources = ResourceUtils.generateResources("r", 10);
		settings.stepCount = 10;
		IExperimentContext experimentContext = settings.getExperimentContextFactory().newContext(settings);
		IEconomicAgent agent =
			agentsCreator.automata2agents(new INode[] {n1}, experimentContext)[0];
		AutomataAgent automataAgent = extractAutomAg(agent);
		Assert.assertEquals("1", automataAgent.getState().getName());
		automataAgent.processProduceStage();
		Assert.assertEquals("2", automataAgent.getState().getName());
	}
	
	private AutomataAgent extractAutomAg(IEconomicAgent agent) {
		Class<?> clazz = agent.getClass();
		clazz = clazz.getSuperclass();
		Field f = null;
		try {
			f = clazz.getDeclaredField("subagent");
		} catch (Exception e) {
			return null;
		}
		Object r = null;
		try {
			f.setAccessible(true);
			r = f.get(agent);
		} catch (Exception e) {
			return null;
		}
		return (AutomataAgent) r;
	}

	public void testProvideSingleResourceAgent() {
		IResourceType wood = new ResourceType("Wood");
		NaturalResourceRedestributionSystem nrrs = 
			new NaturalResourceRedestributionSystem();
		IEconomicAgent psra = new ProvideSingleResourceAgent(nrrs, wood, 1.0);
		Assert.assertTrue(psra instanceof IPreActServiceAgent);
		Assert.assertEquals(0.0, nrrs.howMuchWasStored(wood));
		psra.processPreProduceStage();
		Assert.assertEquals(1.0, nrrs.howMuchWasStored(wood));
	}

	public void testActIFFinRangeOfStepsAgent() {
		IResourceType foodType = new ResourceType("Food"); 
		IResourceType excrementType = new ResourceType("Excrement");
		NaturalResourceRedestributionSystem nrrs = 
			new NaturalResourceRedestributionSystem();
		IEconomicProducer tamagooci = new tests.fakes.TamagoochiAgent(
				foodType, 
				excrementType,
				nrrs
		);
		IEconomicEngine engine = new EconomicEngine();
		int[] sharedint = new int[1];
		IEconomicProducer aiffAgent = new ActIFFinRangeOfStepsAgent(
				tamagooci,
				sharedint, 
				1, 
				1
		);
		engine.addAgents(aiffAgent);
		nrrs.storeResource(foodType, 1.0);
		engine.processSteps(1, nrrs);
		Assert.assertEquals(1.0, nrrs.howMuchWasStored(foodType));
		Assert.assertEquals(0.0, nrrs.howMuchWasStored(excrementType));
		sharedint[0] = 1;
		engine.processSteps(1, nrrs);
		Assert.assertEquals(0.0, nrrs.howMuchWasStored(foodType));
		Assert.assertEquals(100.0, nrrs.howMuchWasStored(excrementType));
		nrrs.storeResource(foodType, 1.0);
		sharedint[0] = 2;
		engine.processSteps(1, nrrs);
		Assert.assertEquals(1.0, nrrs.howMuchWasStored(foodType));
		Assert.assertEquals(100.0, nrrs.howMuchWasStored(excrementType));
	}
}
